既存のAWS環境を後からTerraformでコード化する
はじめに
こんにちは、岩城です。 既存のAWS環境をTerraformでコード化する機会がありました。その際、Terraform素人であったため、コード化する流れを掴むまでに少し時間が掛かりました。 同じような方に向けて、備忘録として残しておきます。
用語解説
Terraform
- Infrastructure as Codeを実現するためのツール
- コードからインフラの構築/変更/バージョン管理を行える
- HashiCorp社が開発、オープンソース版とエンタープライズ版がある
- AWS、Azure、GCPを始めとするメジャーなクラウドプロバイダをサポートしている
- Providers
- 各クラウドの管理ツールで使わずにTerraformで管理できる
- AWS: Cloud Formation
- Azure: Resource Manager
- GCP: Deployment Manager
- コミュニティが活発でリリースが早いAWSのサービスに追従している
- 中にはサポートされていないサービスやサービス内の個別パラメータもある
- バイナリを実行パスに配置しておけば動作するので導入が簡単
Terraformの構成ファイル
本エントリで登場するTerraformの構成ファイルを紹介します。実際にはもっとあります。
- xxxxxxx.tfstate
- Terraformで管理してるインフラの状態が記述されたファイル
- xxxxxxx.tf(tfファイル)
- Terraformのコードが記述された設定ファイル
Terraformのコマンド
本エントリで登場するTerraformのコマンドを紹介します。実際にはもっとあります。
terraform init
- Terraformの設定ファイルを含む作業ディレクトリを初期化します
terraform plan
- 実行計画を作成します。既にTerraformでコード化された環境ならば、実際のリソースやパラメータを変更することなく、パラメータレベルで変更点を確認できます
terraform state show <リソース.リソース名>
- tfstate内の各リソースの状態を確認します
本エントリには登場しませんが、リソースを作成・削除するコマンドも紹介しておきます。
terraform apply
- 設定ファイルに従ってリソースを作成します
terraform destroy
- Terraformが管理するリソースを削除します
Terraformが初めてで興味がお有りの方はこちら
以下を参考にセットアップや基本的な操作方法を確認してみてください。
既存のAWS環境をTerraformでコード化する流れ
お待たせしました。本題です。コード化する流れは以下のような感じです。
- 作業ディレクトリの作成
- プロバイダを指定したtfファイルを作成する
terraform init
する- リソースタイプと名前を定義したtfファイルを作成する
- リソースタイプや個別パラメータについては、とても分かり易い公式ドキュメントを参照しながら定義します
terraform import
するterraform state show
してtfファイルにパラメータを定義するterraform plan
して差分がなくなるまでtfファイルを修正する
上記フローを見ただけでは分かりませんよね。実際にやってみます。
やってみた
構成
今回は、コード化の流れを掴むことを目的にしているので、VPCとサブネットだけの構成です。
仮にEC2を追加したとしても、やることは変わらないと思います。 モジュール化するパターンもあるかと思いますが、私自身まだ勉強中なので今回は触れません。
初期設定
作業ディレクトリでTerraformを実行できるように準備します。
- 作業ディレクトリを作成する
- プロバイダにAWSを指定する設定ファイルを作成する
$ cat provider.tf provider "aws" { region = "ap-northeast-1" }
terraform init
により初期化する
$ terraform init Initializing provider plugins... ~省略~ * provider.aws: version = "~> 1.60" Terraform has been successfully initialized! ~省略~
VPC
はじめにVPCをコード化します。
- VPCに対応したリソースタイプと名前(自由)を宣言したtfファイルを予め作成する
- ここでは
network.tf
ファイルを作成してVPCリソースを定義します
$ cat network.tf resource "aws_vpc" "terraform-sample-vpc" { }
- tfファイルで宣言したリソースタイプと名前、そしてVPCを特定するIDを指定して
terraform import
する - VPCのIDを特定するには、マネジメントコンソールやCLIで確認します
$ terraform import aws_vpc.terraform-sample-vpc
terraform state show
してリソース情報を確認する
$ terraform state show aws_vpc.terraform-sample-vpc id = vpc-xxxxxxxxxxxxxxxxx arn = arn:aws:ec2:ap-northeast-1:xxxxxxxxxxxx:vpc/vpc-xxxxxxxxxxxxxxxxx assign_generated_ipv6_cidr_block = false cidr_block = 10.10.0.0/16 default_network_acl_id = acl-xxxxxxxxxxxxxxxxx default_route_table_id = rtb-xxxxxxxxxxxxxxxxx default_security_group_id = sg-xxxxxxxxxxxxxxxxx dhcp_options_id = dopt-xxxxxxxx enable_classiclink = false enable_classiclink_dns_support = false enable_dns_hostnames = false enable_dns_support = true instance_tenancy = default ipv6_association_id = ipv6_cidr_block = main_route_table_id = rtb-xxxxxxxxxxxxxxxxx owner_id = xxxxxxxxxxxx tags.% = 1 tags.Name = terraform-sample-vpc
- tfstateファイルを元にtfファイルのパラメータを記述する
- 以下の例では、デフォルト値は記載せず定義必須なパラメータやデフォルト値から変更したパラメータを定義します
$ cat network.tf resource "aws_vpc" "terraform-sample-vpc" { cidr_block = "10.10.0.0/16" enable_dns_hostnames = true tags { Name = "terraform-sample-vpc" } }
terraform plan
して変更がないことを確認する
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. aws_vpc.terraform-sample-vpc: Refreshing state... (ID: vpc-xxxxxxxxxxxxxxxxx) ------------------------------------------------------------------------ No changes. Infrastructure is up-to-date. ~省略~
Subnet
次にSubnetをコード化します。VPCを作成した時と流れは一緒です。
- tfファイルを予め作成する
- VPCと同じtfファイルに追記していますが、あくまで一例です。別のファイルで管理しても問題ありません
$ cat network.tf resource "aws_vpc" "terraform-sample-vpc" { cidr_block = "10.10.0.0/16" enable_dns_hostnames = true tags { Name = "terraform-sample-vpc" } } resource "aws_subnet" "terraform-sample-subnet-1a" { }
- Subnet IDを指定して
terraform import
する
$ terraform import aws_subnet.terraform-sample-subnet-1a
terraform state show
でリソース情報を確認する
$ terraform state show aws_subnet.terraform-sample-subnet-1a id = subnet-xxxxxxxxxxxxxxxxx arn = arn:aws:ec2:ap-northeast-1:xxxxxxxxxxxx:subnet/subnet-xxxxxxxxxxxxxxxxx assign_ipv6_address_on_creation = false availability_zone = ap-northeast-1a availability_zone_id = apne1-az4 cidr_block = 10.10.11.0/24 ipv6_cidr_block = ipv6_cidr_block_association_id = map_public_ip_on_launch = false owner_id = xxxxxxxxxxxx tags.% = 1 tags.Name = terraform-sample-subnet-1a vpc_id = vpc-xxxxxxxxxxxxxxxxx
- tfstateファイルを元にtfファイルのパラメータを記述する
- Terraformは作成したリソースのID情報を保持するため、変数で参照することで、IDをハードコーディングせずに済みます
$ cat network.tf resource "aws_vpc" "terraform-sample-vpc" { cidr_block = "10.10.0.0/16" enable_dns_hostnames = true tags { Name = "terraform-sample-vpc" } } resource "aws_subnet" "terraform-sample-subnet-1a" { availability_zone = "ap-northeast-1a" cidr_block = "10.10.11.0/24" vpc_id = "${aws_vpc.terraform-sample-vpc.id}" tags { Name = "terraform-sample-subnet-1a" } }
terraform plan
して変更がないことを確認する
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. aws_vpc.terraform-sample-vpc: Refreshing state... (ID: vpc-xxxxxxxxxxxxxxxxx) aws_subnet.terraform-sample-subnet-1a: Refreshing state... (ID: subnet-xxxxxxxxxxxxxxxxx) ------------------------------------------------------------------------ No changes. Infrastructure is up-to-date. ~省略~
おわりに
弊社にJOINする前は、管理ツールを使わないレガシーなオンプレだけに関わって来ました。今回の機会で実際に体験して、インフラをコードで管理することができるのは、すごいことだなーと感じました。一方で、単に全てコード化したとしても、費用対効果が薄い場面があるとも感じました。例えば、頻繁に同様の環境を構築する機会があったり、DRを考えてのことならコード化する価値はあると思います。コード化して何をやりたいのか明確でないと、コード化できて満足して終わり、なんてことがありそうです。とはいえ、コード化するまでに苦労はありますが、コマンド1発でインフラが構築されるのはとても気持ちが良いです。TerraformだけでなくCloudFormationも扱える両刀使いを目指してこれからも勉強していきます。
本エントリがどなたかのお役に立てれば幸いです。